package com.editors;

/**
 * @author Piazza Francesco Giovanni ,Tecnes Milano http://www.tecnes.com
 *
 */
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.RepaintManager;
import javax.swing.TransferHandler;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;

import com.LineData;
import com.Point3D;
import com.Polygon3D;
import com.PolygonMesh;



/**
 * @author Piazza Francesco Giovanni ,Tecnes Milano http://www.tecnes.com
 *
 */

public class ObjectEditor extends Editor implements MenuListener,ActionListener{


	public ObjectEditor3DPanel center3D;
	public ObjectEditorTopBottomPanel centerTop;
	public ObjectEditorFrontBackPanel centerFront;
	public ObjectEditorLeftRightPanel centerLeft;
	
	public int HEIGHT=550;
	public int WIDTH=600;

	public int FRONT_VIEW_HEIGHT=300;
	public int FRONT_VIEW_WIDTH=300;

	public int TOP_VIEW_HEIGHT=HEIGHT-FRONT_VIEW_HEIGHT;
	public int TOP_VIEW_WIDTH=300;
	
	

	public int RIGHT_BORDER=320;
	public int BOTTOM_BORDER=100;
	public int NX=4;
	public int NY=0;

	public int MOVX=0;
	public int MOVY=0;
	
	public static int y0=250;
	public static int x0=250;

	public int dx=2;
	public int dy=2;

	public double deltay=0.5;
	public double deltax=0.5;


	

	public int MAX_STACK_SIZE=10;

	public JFileChooser fc;
	public JMenuBar jmb;
	public JMenu jm;
	public JMenuItem jmt11;

	
	public boolean redrawAfterMenu=false;
	public AbstractButton jmt12;
	public JMenuItem jmt21;
	public JMenuItem jmt22;
	public JMenuItem jmt23;
	public JMenu jm2;

	public boolean ISDEBUG=false;


	public boolean isUseTextures=true;

	public JMenu jm3;
	public JList lineList;
	public JButton selectAll;
	public LineData polygon=new LineData();


	public JMenuItem jmt31;
	private JMenuItem jmt32;
	
	public File currentDirectory=null;
	public JMenu jm4;
	public JMenuItem jmt41;
	public JCheckBoxMenuItem jmt42;
	private JMenu jm5;
	private JMenuItem jmt51;
	private JMenuItem jmt52;
	private JMenuItem jmt53;
	private JMenuItem jmt54;



	public static Color BACKGROUND_COLOR=new Color(0,0,0);
	
	
	int VIEW_TYPE_3D=0;
	int VIEW_TYPE_TOP=1;
	int VIEW_TYPE_LEFT=2;
	int VIEW_TYPE_FRONT=3;
	int VIEW_TYPE=VIEW_TYPE_3D;
	private JMenuItem jmt55;
	

	public static void main(String[] args) {

		ObjectEditor re=new ObjectEditor();
		
	}

	private void initialize() {
		
		center3D.initialize();
		centerTop.initialize();
	}

	public ObjectEditor(){

		setTitle("Object editor");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(null);
		setSize(WIDTH+RIGHT_BORDER,HEIGHT+BOTTOM_BORDER);
		
		center3D=new ObjectEditor3DPanel(this);
		center3D.setBackground(BACKGROUND_COLOR);
		center3D.setBounds(0,0,WIDTH+RIGHT_BORDER,HEIGHT+BOTTOM_BORDER);
		center3D.setTransferHandler(new FileTransferhandler());
		
		centerTop=new ObjectEditorTopBottomPanel(this);
		centerTop.setBackground(BACKGROUND_COLOR);
		centerTop.setBounds(0,0,WIDTH+RIGHT_BORDER,HEIGHT+BOTTOM_BORDER);
		centerTop.setTransferHandler(new FileTransferhandler());
		
		centerLeft=new ObjectEditorLeftRightPanel(this);
		centerLeft.setBackground(BACKGROUND_COLOR);
		centerLeft.setBounds(0,0,WIDTH+RIGHT_BORDER,HEIGHT+BOTTOM_BORDER);
		centerLeft.setTransferHandler(new FileTransferhandler());
		
		centerFront=new ObjectEditorFrontBackPanel(this);
		centerFront.setBackground(BACKGROUND_COLOR);
		centerFront.setBounds(0,0,WIDTH+RIGHT_BORDER,HEIGHT+BOTTOM_BORDER);
		centerFront.setTransferHandler(new FileTransferhandler());
		

		add(center3D);

		
		buildMenuBar();

		RepaintManager.setCurrentManager( 
				new RepaintManager(){

					public void paintDirtyRegions() {


						super.paintDirtyRegions();
						if(redrawAfterMenu ) {
							getCenter().displayAll();
							redrawAfterMenu=false;						    
						}
					}

				}				
		);
		
		setVisible(true);
		initialize();

	}
	
	public ObjectEditorPanel getCenter(){
		
		if(VIEW_TYPE==VIEW_TYPE_3D)
			return center3D;
		else if(VIEW_TYPE==VIEW_TYPE_TOP)
		    return centerTop;
		else if(VIEW_TYPE==VIEW_TYPE_LEFT)
		    return centerLeft;
		else 
		    return centerFront;
		
	}

	public void paint(Graphics arg0) {
		super.paint(arg0);
		getCenter().displayAll();
		
		
	}

	public Area clipPolygonToArea2D(Polygon p_in,Area area_out){


		Area area_in = new Area(p_in);

		Area new_area_out = (Area) area_out.clone();
		new_area_out.intersect(area_in);

		return new_area_out;

	}


	private void buildMenuBar() {
		jmb=new JMenuBar();
		jm=new JMenu("Load");
		jm.addMenuListener(this);
		jmb.add(jm);

		/*jmt11 = new JMenuItem("Load road");
		jmt11.addActionListener(this);
		jm.add(jmt11);*/

		jmt12 = new JMenuItem("Load Mesh");
		jmt12.addActionListener(this);
		jm.add(jmt12);

		jm2=new JMenu("Save");
		jm2.addMenuListener(this);

		jmt21 = new JMenuItem("Save mesh");
		jmt21.addActionListener(this);
		jm2.add(jmt21);

		jmt22 = new JMenuItem("Save poly format");
		jmt22.addActionListener(this);
		jm2.add(jmt22);

		jmt23 = new JMenuItem("Save base texture");
		jmt23.addActionListener(this);
		jm2.add(jmt23);
		
		jmb.add(jm2);

		jm3=new JMenu("Change");
		jm3.addMenuListener(this);
		jmt31 = new JMenuItem("Undo last");
		jmt31.setEnabled(false);
		jmt31.addActionListener(this);
		jm3.add(jmt31);
		jmt32 = new JMenuItem("Transform");
		jmt32.addActionListener(this);
		jm3.add(jmt32);
	
	
		jmb.add(jm3);
		
		jm4=new JMenu("Edit");
		jm4.addMenuListener(this);
		jmt41 = new JMenuItem("Insert template");	
		jm4.add(jmt41);	
		jmt41.addActionListener(this);
		
		jmt42 = new JCheckBoxMenuItem("Show normals");
		jmt42.setState(false);
		jmt42.addActionListener(this);
		jm4.add(jmt42);
		
		jmb.add(jm4);
		
		jm5=new JMenu("View");
		jm5.addMenuListener(this);
		jmt51 = new JMenuItem("3D view");	
		jm5.add(jmt51);	
		jmt51.addActionListener(this);
		
		jmt52 = new JMenuItem("Top view");
		jmt52.addActionListener(this);
		jm5.add(jmt52);
		
		jmt53 = new JMenuItem("Left view");
		jmt53.addActionListener(this);
		jm5.add(jmt53);
		
		jmt54 = new JMenuItem("Front view");
		jmt54.addActionListener(this);
		jm5.add(jmt54);
		
		jm5.addSeparator();
		
		jmt55 = new JMenuItem("Preview");
		jmt55.addActionListener(this);
		jm5.add(jmt55);
		
		jmb.add(jm5);
		
		
		
		setJMenuBar(jmb);
	}

	public void actionPerformed(ActionEvent arg0) {
		Object o=arg0.getSource();

		if(o==jmt21){
			saveLines();
		}
		else if(o==jmt22){
			savePolyFormat();
		}
		else if(o==jmt23){
			saveBaseCubicTexture();
		}
		else if(o==jmt12){
			loadPointsFromFile();
		}
		else if(o==jmt31){
			undo();
		}
		else if(o==jmt32){
			transform();
		}
		else if(o==jmt51){
			set3DView();
		}
		else if(o==jmt52){
			
			setTopView();
		}
		else if(o==jmt53){
			
			setLeftView();
		}
		else if(o==jmt54){
			
			setFrontView();
		}
		else if(o==jmt55){
			
			preview();
		}
	}




	private void preview() {
		
		
		ObjectEditorPreviewPanel oepp=new ObjectEditorPreviewPanel(this);
		
	}

	public void set3DView() {
		
		remove(getCenter()); 
		VIEW_TYPE=VIEW_TYPE_3D;
		add(center3D);		
		center3D.grabFocus();
		repaint();
	}
	
	public void setTopView() {

		remove(getCenter()); 
		VIEW_TYPE=VIEW_TYPE_TOP;
		add(centerTop);		
		centerTop.grabFocus();
		repaint();
	}
	
	public void setLeftView() {
		
		remove(getCenter()); 
		VIEW_TYPE=VIEW_TYPE_LEFT;
		add(centerLeft);		
		centerLeft.grabFocus();
		repaint();
	}
	
	public void setFrontView() {
		
		remove(getCenter()); 
		VIEW_TYPE=VIEW_TYPE_FRONT;
		add(centerFront);		
		centerFront.grabFocus();
		repaint();
	}

	public void getTemplate() {
		
		ObjectEditorTemplatePanel oetp=new ObjectEditorTemplatePanel();
		
		PolygonMesh pm=oetp.getTemplate();
		
		if(pm!=null){
			points=new Vector();
			for (int i = 0; i < pm.points.length; i++) {
				points.add(pm.points[i]);
			}
			lines=pm.polygonData;
			getCenter().displayAll();
		}
		
	}

	private void transform() {
		
		
		ObjectEditorTransformPanel oetp=new ObjectEditorTransformPanel(this);
		
	}



	private void deselectAllPoints() {
		
		for(int i=0;i<points.size();i++){

			Point3D p=(Point3D) points.elementAt(i);
			p.setSelected(false);
		}
		
	}
	
	private void deselectAllLines() {
		
		for(int i=0;i<lines.size();i++){

			LineData ld=(LineData) lines.elementAt(i);
			ld.setSelected(false);
		}
		
	}

	private void saveLines() {

		fc = new JFileChooser();
		fc.setDialogType(JFileChooser.SAVE_DIALOG);
		fc.setDialogTitle("Save lines");
		if(currentDirectory!=null)
			fc.setCurrentDirectory(currentDirectory);
		int returnVal = fc.showOpenDialog(null);

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File file = fc.getSelectedFile();
			currentDirectory=fc.getCurrentDirectory();
			saveLines(file);

		} 


	}

	public void saveLines(File file) {



		PrintWriter pr;
		try {
			pr = new PrintWriter(new FileOutputStream(file));
			pr.print("P=");

			for(int i=0;i<points.size();i++){

				Point3D p=(Point3D) points.elementAt(i);

				pr.print(decomposePoint(p));
				if(i<points.size()-1)
					pr.print("_");
			}	

			pr.print("\nL=");

			for(int i=0;i<lines.size();i++){

				LineData ld=(LineData) lines.elementAt(i);

				pr.print(decomposeLineData(ld));
				if(i<lines.size()-1)
					pr.print("_");
			}	

			pr.close(); 	

		} catch (FileNotFoundException e) {

			e.printStackTrace();
		}
	}
	
	private void savePolyFormat() {
		
		fc = new JFileChooser();
		fc.setDialogType(JFileChooser.SAVE_DIALOG);
		fc.setDialogTitle("Save other format");
		if(currentDirectory!=null)
			fc.setCurrentDirectory(currentDirectory);
		int returnVal = fc.showOpenDialog(null);

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			currentDirectory=fc.getCurrentDirectory();
			File file = fc.getSelectedFile();
			savePolyFormat(file);

		} 
		
	}



	private void savePolyFormat(File file) {



		PrintWriter pr;
		try {
			pr = new PrintWriter(new FileOutputStream(file));
		
			for(int i=0;i<lines.size();i++){

				LineData ld=(LineData) lines.elementAt(i);

				pr.println(decomposePolyFormat(ld));
			
			}	

			pr.close(); 	

		} catch (FileNotFoundException e) {

			e.printStackTrace();
		}
	}


	private void saveBaseCubicTexture() {
		
		fc = new JFileChooser();
		fc.setDialogType(JFileChooser.SAVE_DIALOG);
		fc.setDialogTitle("Save basic texture");
		if(currentDirectory!=null)
			fc.setCurrentDirectory(currentDirectory);
		int returnVal = fc.showOpenDialog(null);

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			currentDirectory=fc.getCurrentDirectory();
			File file = fc.getSelectedFile();
			saveBaseCubicTexture(file);

		}
		
	}


	private void saveBaseCubicTexture(File file) {
		
		Color backgroundColor=Color.green;
		Color back_color=Color.BLUE;
		Color top_color=Color.RED;
		Color left_color=Color.YELLOW;
		Color right_color=Color.ORANGE;
		Color front_color=Color.CYAN;
		
		int IMG_WIDTH=0;
		int IMG_HEIGHT=0;

		int deltaX=0;
		int deltaY=0;
		int deltaX2=0;

		double minx=0;
		double miny=0;
		double minz=0;
		
		double maxx=0;
		double maxy=0;
		double maxz=0;
		
		
	      //find maxs
		for(int j=0;j<points.size();j++){
			
			Point3D point= (Point3D) points.elementAt(j);
			
			if(j==0){
				
				minx=point.x;
				miny=point.y;
				minz=point.z;
				
				maxx=point.x;
				maxy=point.y;
				maxz=point.z;
			}
			else{
				
				maxx=(int)Math.max(point.x,maxx);
				maxz=(int)Math.max(point.z,maxz);
				maxy=(int)Math.max(point.y,maxy);
				
				
				minx=(int)Math.min(point.x,minx);
				minz=(int)Math.min(point.z,minz);
				miny=(int)Math.min(point.y,miny);
			}
			
	
		}
		
		deltaX2=(int)(maxx-minx);
		deltaX=(int)(maxz-minz);
		deltaY=(int)(maxy-miny);
		
		deltaX2=deltaX2+deltaX;
		
		IMG_HEIGHT=(int) deltaY+deltaX+deltaX;
		IMG_WIDTH=(int) (deltaX2+deltaX);
		
		BufferedImage buf=new BufferedImage(IMG_WIDTH,IMG_HEIGHT,BufferedImage.TYPE_INT_RGB);
	
		try {
			Graphics2D bufGraphics=(Graphics2D)buf.getGraphics();
			
			bufGraphics.setColor(backgroundColor);
			bufGraphics.fillRect(0,0,IMG_WIDTH,IMG_HEIGHT);
			bufGraphics.setColor(front_color);
			bufGraphics.fillRect(deltaX,0,deltaX2-deltaX,deltaX);
			bufGraphics.setColor(top_color);
			bufGraphics.fillRect(deltaX,deltaX,deltaX2-deltaX,deltaY);
			bufGraphics.setColor(left_color);
			bufGraphics.fillRect(0,deltaX,deltaX,deltaY);
			bufGraphics.setColor(right_color);
			bufGraphics.fillRect(deltaX2,deltaX,deltaX,deltaY);
			bufGraphics.setColor(back_color);
			bufGraphics.fillRect(deltaX,deltaY+deltaX,deltaX2-deltaX,deltaX);
			
			ImageIO.write(buf,"jpg",file);
			
		} catch (Exception e) {
			
			e.printStackTrace();
		}
		
	}

	public void loadPointsFromFile(){	

		fc=new JFileChooser();
		fc.setDialogType(JFileChooser.OPEN_DIALOG);
		fc.setDialogTitle("Load lines ");
		if(currentDirectory!=null)
			fc.setCurrentDirectory(currentDirectory);

		int returnVal = fc.showOpenDialog(null);

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			currentDirectory=fc.getCurrentDirectory();
			File file = fc.getSelectedFile();
			loadPointsFromFile(file);


		}
	}
	

	public void undo() {
		points=(Vector) oldPoints.pop();
		lines=(Vector) oldLines.pop();
		if(oldPoints.size()==0)
			jmt31.setEnabled(false);
		
		firePropertyChange("ObjectEditorUndo",false,true);
	}
	
	public void prepareUndo() {
		jmt31.setEnabled(true);
		if(oldPoints.size()==MAX_STACK_SIZE){
			
			oldPoints.removeElementAt(0);
			oldLines.removeElementAt(0);
		}
		oldPoints.push(clonePoints(points));
		oldLines.push(cloneLineData(lines));
		
		
	}

	public Vector clonePoints(Vector oldPoints) {
		
		Vector newPoints=new Vector();
		
		for(int i=0;i<oldPoints.size();i++){
			
			Point3D p=(Point3D) oldPoints.elementAt(i);
			newPoints.add(p.clone());
		}
		
		return newPoints;
	}

	public Vector cloneLineData(Vector oldLines) {
		
		Vector newLineData=new Vector();
		
		for(int i=0;i<oldLines.size();i++){

			LineData ld=(LineData) oldLines.elementAt(i);
		
			
			newLineData.add(ld.clone());
		
			
		}
		return newLineData;
	}
	
	public void loadPointsFromFile(File file){

		points=new Vector();
		lines=new Vector();
		
		oldPoints=new Stack();
		oldLines=new Stack();

		try {
			BufferedReader br=new BufferedReader(new FileReader(file));


			String str=null;
			int rows=0;
			while((str=br.readLine())!=null){
				if(str.indexOf("#")>=0 || str.length()==0)
					continue;

				if(str.startsWith("P="))
					buildPoints(points,str.substring(2));
				else if(str.startsWith("L="))
					buildLines(lines,str.substring(2));


			}

			br.close();
			//checkNormals();
		} catch (Exception e) {

			e.printStackTrace();
		}
	}



	private void buildPoints(Vector points, String str) {

		StringTokenizer sttoken=new StringTokenizer(str,"_");

		while(sttoken.hasMoreElements()){

			String[] vals = sttoken.nextToken().split(",");

			Point3D p=new Point3D();

			p.x=Double.parseDouble(vals[0]);
			p.y=Double.parseDouble(vals[1]);
			p.z=Double.parseDouble(vals[2]);

			points.add(p);
		}




	}

	private void buildLines(Vector lines, String str) {

		StringTokenizer sttoken=new StringTokenizer(str,"_");

		while(sttoken.hasMoreElements()){

			String[] vals = sttoken.nextToken().split(",");

			LineData ld=new LineData();

			for(int i=0;i<vals.length;i++)
				ld.addIndex(Integer.parseInt(vals[i]));


			lines.add(ld);
		}




	}

	private String decomposePoint(Point3D p) {
		String str="";

		str=p.x+","+p.y+","+p.z;

		return str;
	}

	private String decomposeLineData(LineData ld) {

		String str="";

		for(int j=0;j<ld.size();j++){

			if(j>0)
				str+=",";
			str+=ld.getIndex(j);

		}

		return str;
	}
	
	private String decomposePolyFormat(LineData ld) {

		String str="";

		for(int j=0;j<ld.size();j++){

			if(j>0)
				str+="_";
			Point3D p=(Point3D) points.elementAt(ld.getIndex(j));
			str+=p.x+","+p.y+","+p.z;

		}

		return str;
	}


	public void menuCanceled(MenuEvent arg0) {
		// TODO Auto-generated method stub

	}

	public void menuDeselected(MenuEvent arg0) {
		redrawAfterMenu=true;

	}

	public void menuSelected(MenuEvent arg0) {
		redrawAfterMenu=false;

	}


	



		
	

	class FileTransferhandler extends TransferHandler{
		
		
		public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
			
			for(int i=0;i<transferFlavors.length;i++){
				
				 if (!transferFlavors[i].equals(DataFlavor.javaFileListFlavor))
					 return false;
			}
		    return true;
		}
	
		public boolean importData(JComponent comp, Transferable t) {
		
			try {
				List list=(List) t.getTransferData(DataFlavor.javaFileListFlavor);
				Iterator itera = list.iterator();
				while(itera.hasNext()){
					
					Object o=itera.next();
					if(!(o instanceof File))
						continue;
					File file=(File) o;
					currentDirectory=file.getParentFile();
					loadPointsFromFile(file);
					getCenter().displayAll();
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
			return false;
		}
		
	}

	public void checkNormals(){ 
		
		for(int i=0;i<lines.size();i++){
			LineData ld=(LineData) lines.elementAt(i);
			Polygon3D pol=getBodyPolygon(ld);
			//System.out.println(i+": "+Road.findBoxFace(pol));
		}
		
		
	}

	public Polygon3D getBodyPolygon(LineData ld) {
		
		Polygon3D pol=new Polygon3D(ld.size());
		
		for(int i=0;i<ld.size();i++){
			int index=ld.getIndex(i);
			Point3D p=(Point3D) points.elementAt(index);			
			pol.xpoints[i]=(int) p.x;
			pol.ypoints[i]=(int) p.y;
			pol.zpoints[i]=(int) p.z;
		} 
		
		return pol;
		
	}
	
	public static double[][] getRotationMatrix(Point3D versor,double teta){

		return getRotationMatrix(versor.x,versor.y,versor.z,teta);
	}

	/**
	 * 
	 * 
	 *  ROTATION MATRIX OF TETA AROUND (X,Y,Z) AXIS
	 * 
	 * @param x
	 * @param y
	 * @param z
	 * @param teta
	 * @return
	 */



	public static double[][] getRotationMatrix(double x,double y,double z,double teta){

		double[][] matrix=new double[3][3];
		matrix[0][0]=Math.cos(teta)+x*x*(1.0-Math.cos(teta));
		matrix[0][1]=y*x*(1.0-Math.cos(teta))-z*Math.sin(teta);
		matrix[0][2]=z*x*(1.0-Math.cos(teta))+y*Math.sin(teta);
		matrix[1][0]=y*x*(1.0-Math.cos(teta))+z*Math.sin(teta);
		matrix[1][1]=Math.cos(teta)+y*y*(1.0-Math.cos(teta));
		matrix[1][2]=z*y*(1.0-Math.cos(teta))-x*Math.sin(teta);
		matrix[2][0]=z*x*(1.0-Math.cos(teta))-y*Math.sin(teta);
		matrix[2][1]=z*y*(1.0-Math.cos(teta))+x*Math.sin(teta);
		matrix[2][2]=Math.cos(teta)+z*z*(1.0-Math.cos(teta));
		return matrix;
	} 
	
	/**
	 * ROTATE AROUND POINT (X0,Y0,Z0) WITH MATRIX MATRIX
	 * 
	 * 
	 * @param ds
	 * @param matrix
	 * @param x0
	 * @param y0
	 * @param z0
	 */

	public static void rotate(Point3D p,double[][] matrix, double x0,double y0, double z0) {

		double xx=(p.x-x0);
		double yy=(p.y-y0);
		double zz=(p.z-z0);

		p.x=matrix[0][0]*xx+matrix[0][1]*yy+matrix[0][2]*zz+x0;
		p.y=matrix[1][0]*xx+matrix[1][1]*yy+matrix[1][2]*zz+y0;
		p.z=matrix[2][0]*xx+matrix[2][1]*yy+matrix[2][2]*zz+z0;
		


	}



	public static void rotate(Point3D[] ds,double[][] matrix, double x0,double y0, double z0) {

		for(int i=0;i<ds.length;i++){

			rotate( ds[i],matrix,x0,y0,z0);
		}

	}

	public static void rotate(Vector vector,double[][] matrix, double x0,double y0, double z0) {

		for(int i=0;i<vector.size();i++){

			rotate( (Point3D) vector.elementAt(i),matrix,x0,y0,z0);
		}

	}
    
    public void addPropertyChangeListener(PropertyChangeListener listener) {
    	
    	center3D.addPropertyChangeListener(listener);
    	centerTop.addPropertyChangeListener(listener);
    	centerLeft.addPropertyChangeListener(listener);
    	centerFront.addPropertyChangeListener(listener);
    }



}
